import math
from importlib_metadata import re
import matplotlib.pyplot as plt
import numpy as np
import os
import sys
path=os.getcwd()
sys.path.append(path)
from Smartcity_CNN_Fish.algorithm.train import predict
#import torch
import platform
path=""
if platform.system().lower() == 'windows':
    path=".\\Smartcity_CNN_Fish\\weight\\model_num_epochs_1000.pt"
elif platform.system().lower() == 'linux':
	path="./Smartcity_CNN_Fish/weight/model_num_epochs_1000.pt"
class fish:
    def __init__(self, div, number, visual, step, try_time, delta):
        # 初始化
        self.div = div
        self.number = number
        self.visual = visual
        self.step = step
        self.try_time = try_time
        self.delta = delta
    def distance(self, f):
        # 计算self鱼和f鱼之间的距离
        ll = len(self.number)
        res = np.zeros(ll)
        for i in range(ll):
            res[i] = res[i] + (np.squeeze(self.number)[i] - np.squeeze(f.number)[i]) * (np.squeeze(self.number)[i] - np.squeeze(f.number)[i])
        #print("res:",res)
        result=[]
        for r in res:
            result.append(math.sqrt(r))
        return  result
    def func(self):
        #print( np.squeeze(predict(self.number,path)))
        return  np.squeeze(predict(self.number,path))
    def prey(self):
        # 捕食操作
        pre = self.func()
        for i in range(self.try_time):
            rand = np.random.randint(-99, 99, self.div) / 100 * self.visual
            # for j in range(self.div):
            #     self.number[j] = self.number[j] + rand[j]
            self.number=self.number+rand
            cur = self.func()
            if cur > pre:
                # 捕食成功
                # print('原始分数：' + str(pre) + '新分数：' + str(cur) + '捕食成功！！')
                return cur
            else:
                '''
                author: ytc
                description: 鱼群算法中单个数字还原
                '''                
                # 捕食失败
                # for j in range(self.div):
                #     print("selfnumber:",self.number)
                #     print("rand:",rand)
                #     self.number[j] = self.number[j] - rand[j]
                # print("捕食失败！")
            self.number=self.number-rand   
        return pre
    def swarm(self, fishes):
        # 聚群行为：向视觉内鱼群中心前进step
        close_swarm = find_close_swarm(fishes, self)
        center_f = center_fish(close_swarm)
        n = len(close_swarm) - 1
        if n != 0 and (center_f.func() / n > self.delta * self.func()):
            # print("聚群运动")
            for i in range(self.div):
                self.number[0][i] = self.number[0][i] + self.step[i]* (center_f.number[0][i]-self.number[0][i])/self.number[0][i]
            return self.func()
        else:
            # print("随机运动")
            return self.rand()
    def rand(self):
        # for i in range(self.div):
        #     self.number[i] = self.number[i] + self.step * np.random.uniform(-1, 1, 1)
        self.number+=self.step * np.random.uniform(-1, 1, 1)
    def follow(self, fishes):
        # 追尾行为：向着视觉内鱼群中目标函数值最优的鱼前进step
        close_swarm = find_close_swarm(fishes, self)
        best_f = best_fish(close_swarm)
        n = len(close_swarm) - 1
        if n != 0 and (best_f.func() / n > self.delta * self.func()):
            # 向前移动
            # print("向前移动")
            # for i in range(self.div):
            #     self.number[i] = self.number[i] + self.step * (best_f.number[i] - self.number[i])/self.number[i]
            self.number=self.number+self.step*(best_f.number-self.number)/self.number
            return self.func()
        else:
            # 随机运动
            # print("随机运动")
            return self.rand()
def find_close_swarm(fishes, fish_):
    # 在种群fishes中查找fish_视觉范围内的鱼
    # 输入为fishes，是一个list型变量 和一个fish对象
    # 输出为一个fish list
    res = []
    for fi in fishes:
        if all(fish_.distance(fi) < fish_.visual):
            res.append(fi)
    return res

def center_fish(fishes):
    # 计算当前种群的中心位置，并将其中心位置记为certer_fish以完成聚群操作
    # 输入为fishes，是一个list型变量
    # 输出为一个fish对象
    ll = len(fishes)
    if ll == 0 or ll == 1:
        return None
    res = fish(fishes[0].div, fishes[0].number, fishes[0].visual, fishes[0].step, fishes[0].try_time, fishes[0].delta)
    for i in range(fishes[0].div):
        res.number[0][i] = 0
    for i in range(ll):
        for j in range(res.div):
            res.number[0][j] = res.number[0][j] + fishes[i].number[0][j]
    return res
def best_fish(fishes):
    # 计算当前种群最优个体的位置，并将其返回用于追尾操作
    # 输入为fishes，是一个list型变量
    # 输出为一个fish对象
    ll = len(fishes)
    if ll == 0 or ll == 1:
        return None
    index = -1
    max = 0
    for i in range(ll):
        if index == -1 or max < fishes[i].func():
            index = i
            max = fishes[i].func()
    return fishes[index]
def main():
    fishes = []
    div = 6         # xi中i的大小，e.g. div == 6 --> company consume house_price captial employees population
    fish_num = 50   # 鱼群个体数目
    gmax = 500      # 循环最大次数
    tag = 0         # 公告牌
    month_days=30
    init_data=[[400049,994.89,57203,99574,198.27,319.72]]
    #init_data=[2264,7.04,6587,563,5.01,251.93]
    init_gdp=predict(init_data,path)
    rate=0.1
    rate_month=rate/12
    rate_cur=rate/12
    visual =np.array([12062,32.79,2183,1303,4.34,1.98])/30
    step =np.array([1949.9264705882354, 4.842401960784314, 485.3480392156863, 248.11764705882354, 0.9473529411764707, 0.33230392156862754])/30
    try_time = 15
    delta = 0.3
    result=[]
    
    
    # 初始化鱼群
    for i in range(fish_num):
        num = init_data+np.random.randint(-99,99,div)/100*visual
        #print(num)
        fi = fish(div, num, visual, step, try_time, delta)
        fishes.append(fi)
    # for g in range(gmax):
    while rate_cur<=rate:
        for i in range(fish_num):
            if fishes[i].func() > tag:
                tag = fishes[i].func()
                if tag>=init_gdp*(1+rate_cur):
                    print("sucess")
                    print("rate_cur: ",rate_cur*100)
                    print("opt_number: ",fishes[i].number)
                    print("tag: ",tag)
                    result.append([fishes[i].number,tag,rate_cur*100])
                    rate_cur+=rate_month

        for i in range(fish_num):
            if tag == fishes[i].func():
                fishes[i].prey()
                continue
            tmp = np.random.randint(0, 3, 1)
            if tmp == 0:
                fishes[i].swarm(fishes)
            elif tmp == 1:
                fishes[i].follow(fishes)
            else:
                fishes[i].prey()
    # print(result)
    for i in range(len(result)):
        print("优化2022年-{}月".format(i+1))
        print("各项参数指标：{}".format(np.squeeze(result[i][0])))
        print("优化gdp：{}".format(result[i][1]))
        print("目前优化比例{}%".format(result[i][2]))


if __name__ == '__main__':
    main()